package com.bootstrap.widget; import android.animation.Animator; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.graphics.Paint; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.support.v4.view.ViewCompat; import android.util.AttributeSet; import android.view.View; import android.view.animation.DecelerateInterpolator; import com.bootstrap.animation.AbstractAnimatorListener; import com.bootstrap.utils.ColorUtils; import com.squareup.picasso.Picasso; import com.squareup.picasso.Target; public final class MaterialImageView extends View implements Target { private int currentLayerType; private RectF rect; private Paint paint; private Bitmap bitmap; private Runnable loadAction; private ValueAnimator animator; public MaterialImageView(final Context context) { super(context); init(); } public MaterialImageView(final Context context, final AttributeSet attrs) { super(context, attrs); init(); } public MaterialImageView(final Context context, final AttributeSet attrs, final int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } public MaterialImageView setLoadAction(final Runnable runnable) { loadAction = runnable; return this; } private void init() { rect = new RectF(); paint = new Paint(Paint.ANTI_ALIAS_FLAG); } public void setBitmap(final Bitmap bitmap) { this.bitmap = bitmap; } @Override protected void onDraw(final Canvas canvas) { if (bitmap != null) { canvas.drawBitmap(bitmap, rect.left, rect.top, paint); } } @Override protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh) { super.onSizeChanged(w, h, oldw, oldh); rect.set(0f, 0f, w, h); if (bitmap != null) { rect.inset((rect.width() - bitmap.getWidth()) / 2, (rect.height() - bitmap.getHeight()) / 2); } } @Override public void onBitmapLoaded(final Bitmap bitmap, final Picasso.LoadedFrom from) { if (loadAction != null) { loadAction.run(); loadAction = null; } this.bitmap = bitmap; final ColorMatrix contrastMatrix = new ColorMatrix(); final ColorMatrix saturationMatrix = new ColorMatrix(); final ColorMatrix resultMatrix = new ColorMatrix(); animator = ValueAnimator.ofFloat(0f, 4f); animator.setInterpolator(new DecelerateInterpolator(1.5f)); animator.setDuration(3000L); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(final ValueAnimator animation) { final float value = (float) animation.getAnimatedValue(); final float alpha = Math.min(value, 2f) / 2f; // dt = 2, v = [0.0, 1.0] final float contrast = Math.min(value, 3f) / 3f - 1f; // dt = 3, v = [-1.0, 0.0] final float saturation = value / 4f - 1f; // dt = 4, v = [-1.0, 0.0] ColorUtils.alpha(alpha, contrastMatrix); ColorUtils.contrast(contrast, contrastMatrix); ColorUtils.saturation(saturation, saturationMatrix); resultMatrix.setConcat(contrastMatrix, saturationMatrix); paint.setColorFilter(new ColorMatrixColorFilter(resultMatrix)); ViewCompat.postInvalidateOnAnimation(MaterialImageView.this); } }); animator.addListener(new AbstractAnimatorListener() { @Override public void onAnimationStart(final Animator animation) { currentLayerType = getLayerType(); setLayerType(LAYER_TYPE_HARDWARE, null); } @Override public void onAnimationEnd(final Animator animation) { setLayerType(currentLayerType, null); } }); animator.start(); } @Override public void onBitmapFailed(final Drawable errorDrawable) { } @Override public void onPrepareLoad(final Drawable placeHolderDrawable) { } @Override protected void onDetachedFromWindow() { if (animator != null && animator.isRunning()) { animator.cancel(); } super.onDetachedFromWindow(); } }